﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
//using Gma.UserActivityMonitor;
using PropertyGridEx;



namespace MercuryFE
{
    public partial class frmConfig : Form
    {

        #region fields
        List<KeyValuePair<int, string>> _emulatorList = null;
        List<KeyValuePair<int, string>> _customGameList = null;

        string _dataLoadType = "";
        private string _error = "";

        private Inputs _inputs = null;
        private Timer _timer = null;


        private const int _timerDelay = 500; 

        #endregion

        public frmConfig()
        {
            InitializeComponent();
        }

        private void frmConfig_Load(object sender, EventArgs e)
        {
            // load all the datasets (will need to move this somewhere else - only need to populate for 
            this.emulatorTableAdapter.Fill(this.launcherDBDataSet.Emulator);
            this.emulatorPathTableAdapter.Fill(this.launcherDBDataSet.EmulatorPath);
            this.configurationTableAdapter.Fill(this.launcherDBDataSet.Configuration);
            this.menuTableAdapter.Fill(this.launcherDBDataSet.Menu);

            initialiseTree();

            string overviewFile = AppDomain.CurrentDomain.BaseDirectory + "misc\\Overview.htm";
            wbOverview.DocumentStream = new FileStream(overviewFile, FileMode.Open);

            populateEmulatorList();
            populateCustomGameList();
            loadConfigPropertyGrid();
            populateFileMetaData();
            showHideGenerateMameInfoButton();
            showHideCopyMameRomButton();
            populateMenuTypes();

        }

        #region Emulators

        void populateEmulatorList()
        {
            _emulatorList = new List<KeyValuePair<int,string>>();
            foreach (KeyValuePair<int, string> item in LauncherLib.getEmulatorList())
                _emulatorList.Add(item);

            lbEmulator.Items.Clear();

            lbEmulator.DataSource = _emulatorList;
            lbEmulator.DisplayMember = "Value";
            lbEmulator.ValueMember = "Key";
            
        }
    
        private void loadEmulatorPropertyGrid(int EmulatorID)
        {
            EmulatorConfig config = null;

            if (EmulatorID > 0)
                config = LauncherLib.getEmulatorConfig(EmulatorID);
            else if (EmulatorID == 0)
            {
                // new entry added
                config = new EmulatorConfig();
                int minId = 0;
                if(_emulatorList.Count > 0)
                    minId = (from x in _emulatorList select x.Key).Min();

                if (minId >= 0)
                    minId = -1;
                else
                    minId--;

                _emulatorList.Add(new KeyValuePair<int, string>(minId, "NEW EMULATOR"));

                lbEmulator.DataSource = null;
                //lbEmulator.Items.Clear();

                lbEmulator.DataSource = _emulatorList;
                lbEmulator.DisplayMember = "Value";
                lbEmulator.ValueMember = "Key";

                lbEmulator.SelectedIndex = lbEmulator.Items.Count - 1;
            }
            else
            {
                config = new EmulatorConfig();

            }


            // get list of configuration files
            string descDir = LauncherLib.getCurrentDirectory() + (LauncherLib.getCurrentDirectory().EndsWith("\\")?"":"\\") + "ConfigDescFiles\\";
            List<string> configDescFiles = new List<string>();
            configDescFiles.Add("");
            foreach(string descFile in Directory.GetFiles(descDir,"*.xml")) {
                configDescFiles.Add(Path.GetFileNameWithoutExtension(descFile));
            }

            

            // clear all existing items
            pgeEmulator.Item.Clear();

            pgeEmulator.Item.Add("Name", config.Name ?? "", false, "Details", "Name used to identify the emulator.", true);
            pgeEmulator.Item.Add("Description", config.Description ?? "", false, "Details", "Description of the emulator, displayed in some screens.", true);
            pgeEmulator.Item.Add("Is Mame?", config.IsMame, false, "Details", "Is this emulator MAME? If so, allows the mame specific data to be utilised.", true);

            pgeEmulator.Item.Add("Location", config.Location ?? "", false, "Details", "Folder where the emulator is located.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].UseFolderEditor = true;


            pgeEmulator.Item.Add("ImageName", config.ImageName ?? "", false, "Details", "Image, located in theme folder, display from client interface.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += ShowImageSelector;


            pgeEmulator.Item.Add("Executable", config.Executable ?? "", false, "Emulator", "The main emulator executable.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].UseFileNameEditor = true;
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameFilter = "All files (*.*)|*.*";

            pgeEmulator.Item.Add("ConfigurationFile", config.ConfigurationFile ?? "", false, "Emulator", "Configuration file used by the emulator.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].UseFileNameEditor = true;
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameFilter = "All files (*.*)|*.*";

            pgeEmulator.Item.Add("Configuration Description File", config.ConfigDescFile ?? "", false, "Emulator", "Configuration description file used to describe/ aid in modifying the actual configuration file. This is required by mame to work correctly.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].Choices = new CustomChoices(configDescFiles.ToArray(), false);
            //pgeEmulator.Item[pgeEmulator.Item.Count - 1].UseFileNameEditor = true;
            //pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            //pgeEmulator.Item[pgeEmulator.Item.Count - 1].FileNameFilter = "XML files (*.xml)|*.xml";

            pgeEmulator.Item.Add("Arguments", config.Arguments ?? "", false, "Emulator", "Arguments passed to emulator when launching game.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += ShowCommandLineEditor;

            // roms
            pgeEmulator.Item.Add("Include Sub Paths", config.RomIncludeSubPaths, false, "Paths - ROM", "Whether to include sub folders when scanning for files.", true);
            pgeEmulator.Item.Add("Search Pattern", config.RomSearchPattern ?? "", false, "Paths - ROM", "Search pattern used when scanning for files.", true);
            string romPaths = "";
            if (config.RomPaths != null && config.RomPaths.Count > 0)
                romPaths = string.Join(";", (from x in config.RomPaths select x.Path).ToArray());

            pgeEmulator.Item.Add("Paths", romPaths, false, "Paths - ROM", "Collection of paths in which to scan for files. (';' delimited)", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += MultiPath_OnClick;

            // snaps
            pgeEmulator.Item.Add("Include Sub Paths", config.SnapIncludeSubPaths, false, "Paths - SNAP", "Whether to include sub folders when scanning for files.", true);
            pgeEmulator.Item.Add("Search Pattern", config.SnapSearchPattern ?? "", false, "Paths - SNAP", "Search pattern used when scanning for files.", true);
            string snapPaths = "";
            if (config.SnapPaths != null && config.SnapPaths.Count > 0)
                snapPaths = string.Join(";", (from x in config.SnapPaths select x.Path).ToArray());

            pgeEmulator.Item.Add("Paths", snapPaths, false, "Paths - SNAP", "Collection of paths in which to scan for files. (';' delimited)", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += MultiPath_OnClick;


            //  movies
            pgeEmulator.Item.Add("Include Sub Paths", config.MovieIncludeSubPaths, false, "Paths - MOVIE", "Whether to include sub folders when scanning for files.", true);
            pgeEmulator.Item.Add("Search Pattern", config.MovieSearchPattern ?? "", false, "Paths - MOVIE", "Search pattern used when scanning for files.", true);
            string moviePaths = "";
            if (config.MoviePaths != null && config.MoviePaths.Count > 0)
                moviePaths = string.Join(";", (from x in config.MoviePaths select x.Path).ToArray());

            pgeEmulator.Item.Add("Paths", moviePaths, false, "Paths - MOVIE", "Collection of paths in which to scan for files. (';' delimited)", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += MultiPath_OnClick;


            // advanced
            pgeEmulator.Item.Add("Pre Load", config.PreLoad ?? "", false, "Pre/Post Operations", "Executed before the emulator launches a game. For example, load a memory resident util.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += ShowMultiLineStringEditor;
            pgeEmulator.Item.Add("Post Load", config.PostLoad ?? "", false, "Pre/Post Operations", "Executed after the emulator has exited. For example, unload a memory resident util.", true);
            pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += ShowMultiLineStringEditor;

            //pgeEmulator.Item.Add("Key Mappings", config.KeyMappingString(), false, "Pre/Post Operations", "Remaps keys for the duration of the emulator being executed. Use custom editor instead of manually modifying.", true);
            //pgeEmulator.Item[pgeEmulator.Item.Count - 1].OnClick += ShowKeyMappingEditor;



            pgeEmulator.Refresh();

        }

        //public object ShowKeyMappingEditor(object sender, EventArgs e)
        //{
        //    CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
        //    string value = prop.Value.ToString();

        //    KeyMapper frm = new KeyMapper(value);
        //    frm.ShowDialog();
        //    value = frm.KeyMappingString;
        //    frm.Dispose();
        //    return value;


        //}

        public object ShowMultiLineStringEditor(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();

            MultiLineStringEditor frmMLSE = new MultiLineStringEditor(value);
            frmMLSE.ShowDialog();
            value = frmMLSE.Value;
            frmMLSE.Dispose();
            return value;


        }

        public object ShowCommandLineEditor(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();


            ArgumentsEditor frmCLE = new ArgumentsEditor(value);
            frmCLE.ShowDialog();
            value = frmCLE.arguments;
            frmCLE.Dispose();
            return value;
        }

        public object ShowImageSelector(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();


            ImageSelectorForm frmIS = new ImageSelectorForm();
            frmIS.ShowDialog();
            value = frmIS.ImageName;
            frmIS.Dispose();
            return value;
        }

        private void saveEmulatorPropertyGrid()
        {
            EmulatorConfig config = new EmulatorConfig();

            int emulatorId = ((KeyValuePair<int, string>)lbEmulator.SelectedItem).Key;
            config.EmulatorID = emulatorId;

            config.Name = getPropertyGridItem(pgeEmulator, "Name", "Details");
            config.Description = getPropertyGridItem(pgeEmulator, "Description", "Details");
            config.IsMame = bool.Parse(getPropertyGridItem(pgeEmulator, "Is Mame?", "Details"));
            config.Location = getPropertyGridItem(pgeEmulator, "Location", "Details");
            config.ImageName = getPropertyGridItem(pgeEmulator, "ImageName", "Details");


            config.Executable = getPropertyGridItem(pgeEmulator, "Executable", "Emulator");
            config.Arguments = getPropertyGridItem(pgeEmulator, "Arguments", "Emulator");



            config.ConfigurationFile = getPropertyGridItem(pgeEmulator, "ConfigurationFile", "Emulator");
            config.ConfigDescFile = getPropertyGridItem(pgeEmulator, "Configuration Description File", "Emulator");
            

            string category = "Paths - ROM";
            config.RomIncludeSubPaths = bool.Parse(getPropertyGridItem(pgeEmulator, "Include Sub Paths", category));
            config.RomSearchPattern = getPropertyGridItem(pgeEmulator, "Search Pattern", category);
            foreach (string path in getPropertyGridItem(pgeEmulator, "Paths", category).Split(';').Distinct().ToList())
            {
                if(path.Trim() != "")
                    config.RomPaths.Add(new EmulatorPathConfig(path, config.RomSearchPattern, config.RomIncludeSubPaths));
            }

            category = "Paths - SNAP";
            config.SnapIncludeSubPaths = bool.Parse(getPropertyGridItem(pgeEmulator, "Include Sub Paths", category));
            config.SnapSearchPattern = getPropertyGridItem(pgeEmulator, "Search Pattern", category);
            foreach (string path in getPropertyGridItem(pgeEmulator, "Paths", category).Split(';').Distinct().ToList())
            {
                if (path.Trim() != "")
                    config.SnapPaths.Add(new EmulatorPathConfig(path, config.SnapSearchPattern, config.SnapIncludeSubPaths));
            }

            category = "Paths - MOVIE";
            config.MovieIncludeSubPaths = bool.Parse(getPropertyGridItem(pgeEmulator, "Include Sub Paths", category));
            config.MovieSearchPattern = getPropertyGridItem(pgeEmulator, "Search Pattern", category);
            foreach (string path in getPropertyGridItem(pgeEmulator, "Paths", category).Split(';').Distinct().ToList())
            {
                if (path.Trim() != "")
                    config.MoviePaths.Add(new EmulatorPathConfig(path, config.MovieSearchPattern, config.MovieIncludeSubPaths));
            }

            category = "Pre/Post Operations";
            config.PreLoad = getPropertyGridItem(pgeEmulator, "Pre Load", category);
            config.PostLoad = getPropertyGridItem(pgeEmulator, "Post Load", category);
            config.KeyMappings = LauncherLib.StringToKeyMapping(getPropertyGridItem(pgeEmulator, "Key Mappings", category));

            string error = "";
            int newEmulatorId = LauncherLib.saveEmulatorConfig(config, ref error);

            if (error != "")
            {
                MessageBox.Show("Error saving emulator configuration" + Environment.NewLine + error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // now update the dropdown with the correct info.
            int index = -1;
            for(int i = 0; i < _emulatorList.Count; i++) {
                if(_emulatorList[i].Key == emulatorId) {
                    index = i;
                }
            }
            KeyValuePair<int, string> newItem = new KeyValuePair<int,string>(newEmulatorId, config.Name);
            _emulatorList[index] = newItem;

            lbEmulator.DataSource = null;

            lbEmulator.DataSource = _emulatorList;
            lbEmulator.DisplayMember = "Value";
            lbEmulator.ValueMember = "Key";

            lbEmulator.SelectedIndex = index;


            // show generate button if we have a mame emulator (or lost one)
            showHideGenerateMameInfoButton();
            showHideCopyMameRomButton();
        }

        private string getPropertyGridItem(PropertyGridEx.PropertyGridEx grid, string name, string category )
        {
            string value = "";
            foreach (PropertyGridEx.CustomProperty item in grid.Item)
            {
                if (item.Name == name && item.Category == category)
                {
                    value = item.Value.ToString();
                }
            }
            return value;
        }

        private object MultiPath_OnClick(object sender, EventArgs e)
        {
            PropertyGridEx.CustomProperty prop = (PropertyGridEx.CustomProperty)((PropertyGridEx.CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();

            PropertyGridEx.MultiItemEditor frmMPE = new PropertyGridEx.MultiItemEditor(value, PropertyGridEx.MultiItemEditor.MultiItemType.Path, ';');
            frmMPE.ShowDialog();
            value = frmMPE.ItemString;
            frmMPE.Dispose();
            return value;
        }

        private void lbEmulator_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lbEmulator.SelectedItem != null)
            {
                int emulatorId = ((KeyValuePair<int, string>)lbEmulator.SelectedItem).Key;
                loadEmulatorPropertyGrid(emulatorId);
            }
        }

        private void btnAddEmulator_Click(object sender, EventArgs e)
        {
            loadEmulatorPropertyGrid(0);
        }

        private void btnSaveCurrentEmulator_Click(object sender, EventArgs e)
        {
            saveEmulatorPropertyGrid();
        }

        private void btnDeleteEmulator_Click(object sender, EventArgs e)
        {
            if (lbEmulator.SelectedItem != null)
            {

                int emulatorId = ((KeyValuePair<int, string>)lbEmulator.SelectedItem).Key;
                if (emulatorId > 0)
                {
                    string error = "";
                    if (!LauncherLib.deleteEmulatorConfig(emulatorId, ref error))
                    {
                        MessageBox.Show("Error deleting emulator configuration" + Environment.NewLine + error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }


                    _emulatorList.RemoveAt(lbEmulator.SelectedIndex);

                    lbEmulator.DataSource = null;
                    //lbEmulator.Items.Clear();

                    lbEmulator.DataSource = _emulatorList;
                    lbEmulator.DisplayMember = "Value";
                    lbEmulator.ValueMember = "Key";


                    if (_emulatorList.Count > 0)
                        lbEmulator.SelectedIndex = lbEmulator.Items.Count - 1;
                    else
                    {
                        pgeEmulator.Item.Clear();
                        pgeEmulator.Refresh();
                    }
                }
            }
        }

        private void btnConfiguration_Click(object sender, EventArgs e)
        {
            string configurationFile = getPropertyGridItem(pgeEmulator, "ConfigurationFile", "Emulator");


            string configDescFile = getPropertyGridItem(pgeEmulator, "Configuration Description File", "Emulator");
            
            if (configDescFile != "")
            {
                string descDir = LauncherLib.getCurrentDirectory() + (LauncherLib.getCurrentDirectory().EndsWith("\\") ? "" : "\\") + "ConfigDescFiles\\";
                configDescFile = descDir + configDescFile + ".xml";

                // double check it exists
                if (!File.Exists(configDescFile))
                    configDescFile = "";
            }

            if (configurationFile == "")
                return;

            ConfigurationEditor ce = new ConfigurationEditor(configurationFile, configDescFile);
            if(ce != null && !ce.IsDisposed)
                ce.ShowDialog();
        }


        #endregion

        #region Configuration

        private void loadConfigPropertyGrid()
        {
            pgeConfig.Item.Clear();
            List<ProgramConfig> configs = LauncherLib.getProgramConfig();
            if (configs != null && configs.Count > 0)
            {
                foreach (ProgramConfig item in configs)
                {
                    pgeConfig.Item.Add(item.Name, item.Value, false, item.Category, item.Description, true);

                    switch (item.DataType)
                    {
                        case "pathSingle":
                            pgeConfig.Item[pgeConfig.Item.Count - 1].UseFolderEditor = true;
                            break;


                        case "multipleChoice":
                            pgeConfig.Item[pgeConfig.Item.Count - 1].Choices = new CustomChoices(item.TypeSettings.Split(',').ToArray(), false);
                            break;

                        case "keycode":
                            pgeConfig.Item[pgeConfig.Item.Count - 1].OnClick += ShowKeyCodeEditor;
                            break;
                        case "mousecode":
                            pgeConfig.Item[pgeConfig.Item.Count - 1].OnClick += ShowMouseCodeEditor;
                            break;
                        case "joycode":
                            pgeConfig.Item[pgeConfig.Item.Count - 1].OnClick += ShowJoystickCodeEditor;
                            break;
                    }

                }
            }
            pgeConfig.Refresh();
        }


        public object ShowKeyCodeEditor(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();

            KeyCode frm = new KeyCode(InputDeviceType.keyboard);
            frm.ShowDialog();
            value = frm.KeycodePressed;
            frm.Dispose();
            return value;
        }

        public object ShowMouseCodeEditor(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();

            KeyCode frm = new KeyCode(InputDeviceType.mouse);
            frm.ShowDialog();
            value = frm.KeycodePressed;
            frm.Dispose();
            return value;
        }

        public object ShowJoystickCodeEditor(object sender, EventArgs e)
        {
            CustomProperty prop = (CustomProperty)((CustomProperty.CustomPropertyDescriptor)sender).CustomProperty;
            string value = prop.Value.ToString();

            KeyCode frm = new KeyCode(InputDeviceType.joystick);
            frm.ShowDialog();
            value = frm.KeycodePressed;
            frm.Dispose();
            return value;
        }

        private void btnSaveConfig_Click(object sender, EventArgs e)
        {
            configurationTableAdapter.Update(this.launcherDBDataSet.Configuration);

        }


        private void btnSaveProgramConfig_Click(object sender, EventArgs e)
        {
            List<ProgramConfig> configs = new List<ProgramConfig>();
            foreach (PropertyGridEx.CustomProperty item in pgeConfig.Item)
            {
                ProgramConfig pc = new ProgramConfig
                {
                    Name = item.Name
                     ,
                    Value = item.Value.ToString()

                };
                configs.Add(pc);
            }
            LauncherLib.saveProgramConfig(configs);
            loadConfigPropertyGrid(); // load it so we remove the 'bolded changed' items


            // reload image options, in case theme path has changed
            //populateImageMenus();
        }
        #endregion

        #region Menu

        private void populateMenuTypes()
        {
            string[] menuTypes = new string[] {"standard","top20","last20","most20", "music"};
            cmbMenuType.Items.Clear();
            cmbMenuType.Items.AddRange(menuTypes);
            
        }

        private void cmbMenuType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode != null && tvMenu.SelectedNode.Tag != null)
            {

                DataRow dr = (DataRow)tvMenu.SelectedNode.Tag;
                string menuType = (string)cmbMenuType.SelectedItem;
                int menuId = (int)dr["MenuID"];

                if (LauncherLib.deleteMenuCollection(menuId, menuType))
                {
                    this.statusStrip1.Text = "Current Menu Items deleted.";
                    dr["MenuType"] = menuType;
                    tvMenu.SelectedNode.Tag = dr;
                }

                if (menuType != "music")
                {
                    btnAddGames.Visible = true;
                    btnAddMusic.Visible = false;
                }
                else
                {
                    // else its music... so must have been something different before
                    btnAddGames.Visible = false;
                    btnAddMusic.Visible = true;
                }
                showMenuItems();
            }
        }

        private void initialiseTree()
        {
            // SETUP CONTEXT MENU
            contextMenu.AutoSize = true;

            //contextMenu.Items.Add(getMenuTextEntry("Description", "txtDescription", ""));
            //contextMenu.Items.Add(getMenuTextEntry("ImageName", "txtImageName", ""));

            //contextMenu.Items.Add(new ToolStripSeparator());

            ToolStripItem tsi = contextMenu.Items.Add("Insert");
            tsi.Click += new EventHandler(menuInsertClick);

            tsi = contextMenu.Items.Add("Move Up");
            tsi.Click += new EventHandler(menuUpClick);

            tsi = contextMenu.Items.Add("Move Down");
            tsi.Click += new EventHandler(menuDownClick);

            tsi = contextMenu.Items.Add("Delete");
            tsi.Click += new EventHandler(menuDeleteClick);

            //contextMenu.Items.Add(new ToolStripSeparator());
            //contextMenu.Opening += new CancelEventHandler(contextMenu_Opening);
            //contextMenu.Closed += new ToolStripDropDownClosedEventHandler(contextMenu_Closed);

            // SETUP TREEVIEW FOR MENU
            // event handlers for tree
            tvMenu.NodeMouseClick += new TreeNodeMouseClickEventHandler(tvMenu_NodeMouseClick);
            tvMenu.Click += new EventHandler(tvMenu_Click);
            tvMenu.AfterLabelEdit += new NodeLabelEditEventHandler(tvMenu_AfterLabelEdit);


            tvMenu.HideSelection = false;

            populateMenuTree();
        }

        public void populateMenuTree()

        {

            tvMenu.Nodes.Clear();
            TreeNode topNode = new TreeNode("Frontend Menu");
            topNode.ContextMenuStrip = contextMenu;

            tvMenu.Nodes.Add(topNode);
            tvMenu.ExpandAll();

            populateMenuTreeChildren(topNode.Nodes, 0); // 0 for null

           // tvMenu.CollapseAll();
           // topNode.FirstNode.Expand();

            tvMenu.ExpandAll();
            
        }

        void tvMenu_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            // change the name to match label
            if (tvMenu.SelectedNode.Tag != null) // ignore changes to root node
            {
                //e.Node.EndEdit(false);
                //e.Node.Text = e.Label;


                string name = e.Label;

                // only bother saving if valid value has been given

                if (name != null && name.Trim() != "")
                {

                    DataRow menuRow = (DataRow)tvMenu.SelectedNode.Tag;

                    menuRow["Name"] = name;

                    tvMenu.SelectedNode.Text = name;
                    saveMenuTree(false);
                }
            }
            
        }

        void tvMenu_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            // make sure that node that is clicked (regardless of mouse click) selects the node
            tvMenu.SelectedNode = e.Node;
        }

        void menuInsertClick(object sender, EventArgs e)
        {
            DataRow dr = this.launcherDBDataSet.Menu.DataSet.Tables["Menu"].NewRow();
            string newText = "New Menu Item";

            TreeNode newNode = new TreeNode(newText);
            TreeNode parentNode = tvMenu.SelectedNode;

            if(parentNode.Tag!=null) // root node is null
                dr["ParentMenuID"] = (int)((DataRow)parentNode.Tag)["MenuID"];

            dr["Name"] = newText;
            newNode.Tag = dr;

            // grab sort order from last child node, + 1
            int newSortOrder = 1;
            if(parentNode.Nodes.Count > 0)
                newSortOrder = (int)((DataRow)parentNode.Nodes[parentNode.Nodes.Count - 1].Tag)["SortOrder"] + 1;

            dr["SortOrder"] = newSortOrder;
            dr["MenuType"] = "standard";
            

            parentNode.Nodes.Add(newNode);
            this.launcherDBDataSet.Menu.DataSet.Tables["Menu"].Rows.Add(dr);

           //MessageBox.Show("Insert clicked");
            //throw new NotImplementedException();
            saveMenuTree(); 
        }

        void menuUpClick(object sender, EventArgs e)
        {
            if(tvMenu.SelectedNode.Tag != null)
                TreeViewUtil.NudgeUp(tvMenu.SelectedNode);
            saveMenuTree(); 
        }

        void menuDownClick(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode.Tag != null)
                TreeViewUtil.NudgeDown(tvMenu.SelectedNode);
            saveMenuTree(); 
        }

        void menuDeleteClick(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode.Tag != null)
            {
    
                string error = "";
                if (!LauncherLib.deleteMenuEntry((int)((DataRow)tvMenu.SelectedNode.Tag)["MenuID"], ref error))
                {
                    MessageBox.Show("Error deleting menu" + Environment.NewLine + error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                TreeViewUtil.DeleteNode(tvMenu, false);

            }
            //saveMenuTree(); 
            this.menuTableAdapter.Fill(this.launcherDBDataSet.Menu);
            populateMenuTree();
        }

        void tvMenu_Click(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode != null && tvMenu.SelectedNode.Tag != null)
            {
                MouseEventArgs mea = (MouseEventArgs)e;
                try
                {
                    if (mea.Button == MouseButtons.Right)
                    {
                        contextMenu.Show();
                    }
                    else if (mea.Button == MouseButtons.Left)
                    {
                        showMenuItems();
                    }

                }
                catch (Exception) { throw; }
            }
            else
            {
                showMenuItems();
            }
        }

        private void saveMenuTree()
        {
            saveMenuTree(true);
        }

        private void saveMenuTree(bool reloadTree)
        {
            // save off the data to db
            menuTableAdapter.Update(this.launcherDBDataSet.Menu);

            if (reloadTree)
            {
                this.menuTableAdapter.Fill(this.launcherDBDataSet.Menu); // reload data from db
                populateMenuTree(); // repopulate tree from DB
                
            }
        }

        private void populateMenuTreeChildren(TreeNodeCollection nodes, int parentMenuId)
        {


            foreach (DataRow dr in launcherDBDataSet.Menu.Rows)
            {
                object[] test =  dr.ItemArray;
                string temp = dr["ParentMenuID"].ToString();

                int currParentMenuId = 0; // default to null if cannot parse (only possibility is null)
                int.TryParse(dr["ParentMenuID"].ToString(), out currParentMenuId);
                if (currParentMenuId == parentMenuId)
                {
                    TreeNode node = new TreeNode();
                    node.Text = dr["Name"].ToString();
                    node.ContextMenuStrip = contextMenu;
                    //node.ToolTipText = dr["Description"].ToString();
                 
                    node.Tag = dr; // add data row to the node
                   //node.Expand();
                    //node.Collapse();
                    nodes.Add(node);

                    populateMenuTreeChildren(node.Nodes, (int)dr["MenuID"]);
                }
            }
        }

        private void showMenuItems()
        {

            this.statusStrip1.Text = "";
            //dgvGames.RowsRemoved -= new System.Windows.Forms.DataGridViewRowsRemovedEventHandler(this.dgvGames_RowsRemoved);


            if (tvMenu.SelectedNode.Tag == null)
            {
                lblGameSearchRecordCount.Text = "Top Level - Cannot assign items.";
                this.launcherDBDataSet.GameSearch.Clear();
                btnAddGames.Visible = false;
                btnAddMusic.Visible = false;
                pnlMenuProperties.Enabled = false;
            }

            else // (tvMenu.SelectedNode.Tag != null)
            {
                pnlMenuProperties.Enabled = true;

                DataRow dr = (DataRow)tvMenu.SelectedNode.Tag;
                string menuType = dr["MenuType"].ToString();

                cmbMenuType.SelectedItem = menuType;

                if (menuType == "standard" || menuType == "music")
                {
                    int menuId = (int)dr["MenuID"];
                    txtMenuDescription.Text = dr["Description"].ToString();
                    string imageName = dr["imageName"].ToString();

                    tbMenuImage.Text = imageName;

                    txtMenuPassword.Text = dr["Password"].ToString();

                    if (menuType == "standard")
                    {

                        int recordCount = this.gameSearchTableAdapter.Fill(this.launcherDBDataSet.GameSearch, menuId);

                        lblGameSearchRecordCount.Text = "Number of Games : " + recordCount.ToString();
                        btnAddGames.Visible = true;
                        dgvGames.Visible = true;
                        btnAddMusic.Visible = false;
                        dgvMusic.Visible = false;

                    }
                    else
                    {
                        int recordCount = this.musicSearchTableAdapter.Fill(this.launcherDBDataSet.MusicSearch, menuId);

                        lblGameSearchRecordCount.Text = "Number of Albums : " + recordCount.ToString();
                        btnAddMusic.Visible = true;
                        dgvMusic.Visible = true;
                        btnAddGames.Visible = false;
                        dgvGames.Visible = false;

                    }




                }
                else
                {
                    lblGameSearchRecordCount.Text = "Cannot assign games to this menu type.";
                    this.launcherDBDataSet.GameSearch.Clear();
                    btnAddGames.Visible = false;
                    btnAddMusic.Visible = false;
                    pnlMenuProperties.Enabled = true;
                }

            }



            //this.dgvGames.RowsRemoved += new System.Windows.Forms.DataGridViewRowsRemovedEventHandler(this.dgvGames_RowsRemoved);
            configStatus.Text = "";
        }

        private void btnAddGames_Click(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode != null && tvMenu.SelectedNode.Tag != null)
            {

                int menuId = (int)((DataRow)tvMenu.SelectedNode.Tag)["MenuID"];
                frmSearch searchForm = new frmSearch(menuId, null);
                // searchForm.FormClosed += new FormClosedEventHandler(searchForm_FormClosed);
                searchForm.ShowDialog();

                if (searchForm.useWizard)
                {
                    this.menuTableAdapter.Fill(this.launcherDBDataSet.Menu); // reload data from db
                    populateMenuTree(); // repopulate tree from DB

                }
                else
                    showMenuItems();

                searchForm.Dispose();
            }
        }

        void searchForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            showMenuItems();
        }

        private void dgvGames_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
        {
            //DataTable dt = (DataTable)dgvGames.DataSource;
            //LauncherLib.updateGamesMenu(dt);
            this.gameSearchTableAdapter.Update(this.launcherDBDataSet.GameSearch);
            configStatus.Text = "Games removed from current menu.";
        }

        private void btnSaveMenuDetails_Click(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode.Tag != null) // ignore changes to root node
            {

                DataRow menuRow = (DataRow)tvMenu.SelectedNode.Tag;
                string imageName = tbMenuImage.Text; // ""; //name = "",

                string description = txtMenuDescription.Text;
                string menuType = cmbMenuType.SelectedItem.ToString();
                //if (cmbMenuImage.SelectedItem != null && cmbMenuImage.SelectedItem.ToString() != "")
                //    imageName = cmbMenuImage.SelectedItem.ToString();

                menuRow["Description"] = description;
                menuRow["ImageName"] = imageName;
                menuRow["MenuType"] = menuType;

                if (txtMenuPassword.Text != "")
                    menuRow["Password"] = txtMenuPassword.Text;
                else
                    menuRow["Password"] = null;

                saveMenuTree(false);
                configStatus.Text = menuRow["Name"].ToString() + " details saved.";
            }
        }

        private void txtMenuPassword_Enter(object sender, EventArgs e)
        {
            _timer = new Timer();

            _inputs = new Inputs(this.Handle, true, false, true); // don't poll mouse..

            _timer.Tick += new EventHandler(_timer_Tick);
            _timer.Interval = 16; // every 16 ms

            _timer.Start();


            //HookManager.KeyDown += new KeyEventHandler(txtMenuPassword_KeyDown);
    
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            // if we have tick set to 1/2 sec, set back again - this stops the numerous registers.
            if (_timer.Interval == _timerDelay)
                _timer.Interval = 16;


            // poll the devices, and if we find something has been triggered, add to password box
            List<InputDeviceState> states = _inputs.pollDevices(true);

            foreach (InputDeviceState ids in states)
            {
                if (!string.IsNullOrEmpty(ids.RawValue))
                {
                    _timer.Interval = _timerDelay; // 1 sec
                    string value = ids.RawValue;

                    if (txtMenuPassword.Text != "")
                        txtMenuPassword.Text += " ";

                    txtMenuPassword.Text += value;


                }
            }
        }

        //void txtMenuPassword_KeyDown(object sender, KeyEventArgs e)
        //{
        //    //MessageBox.Show("keycode=" + e.KeyCode.ToString());

        //    e.SuppressKeyPress = true;

        //    if (txtMenuPassword.Text != "")
        //        txtMenuPassword.Text += " ";

        //    txtMenuPassword.Text += e.KeyCode.ToString();


        //}

        private void txtMenuPassword_Leave(object sender, EventArgs e)
        {
            _timer.Stop();
            _timer.Dispose();

            _inputs.releaseDevices();
            _inputs = null;


           // HookManager.KeyDown -= new KeyEventHandler(txtMenuPassword_KeyDown);

        }

        private void btnMenuDetailsClearPassword_Click(object sender, EventArgs e)
        {
            txtMenuPassword.Text = "";
        }

        private void btnChooseMenuImage_Click(object sender, EventArgs e)
        {
            ImageSelectorForm frmIS = new ImageSelectorForm();
            frmIS.ShowDialog();
            tbMenuImage.Text = frmIS.ImageName;
            frmIS.Dispose();

        }

        private void btnAddMusic_Click(object sender, EventArgs e)
        {
            if (tvMenu.SelectedNode != null && tvMenu.SelectedNode.Tag != null)
            {

                int menuId = (int)((DataRow)tvMenu.SelectedNode.Tag)["MenuID"];
                SearchMusic searchForm = new SearchMusic(menuId);
                // searchForm.FormClosed += new FormClosedEventHandler(searchForm_FormClosed);
                searchForm.ShowDialog();

                //if (searchForm.useWizard)
                //{
                //    this.menuTableAdapter.Fill(this.launcherDBDataSet.Menu); // reload data from db
                //    populateMenuTree(); // repopulate tree from DB

                //}
                //else
                showMenuItems();

                searchForm.Dispose();
            }
        }


#endregion

        #region Data load

        private void showHideGenerateMameInfoButton()
        {
            if (LauncherLib.HasMameEmulatorDefined())
                btnGenerateMameInfo.Enabled = true;
            else
                btnGenerateMameInfo.Enabled = false;
        }

        private void populateFileMetaData()
        {
            Dictionary<string, string> fileMetaInfo = LauncherLib.getMameFileInfo();
            
            string[] files = new string[] { "MameFileInfo", "NPlayers", "CatVer", "Command", "History", "Controls" };
            System.Windows.Forms.Label[] labels = new System.Windows.Forms.Label[] { lblMameInfoMetaData, lblNPlayersMetaData, lblCatVerMetaData, lblCommandMetaData, lblHistoryMetaData, lblControlsMetaData };

            for(int i = 0; i < files.Length; i++)
            {
                string file = files[i];
                if (fileMetaInfo.ContainsKey(file))
                {
                    labels[i].Text = fileMetaInfo[file];
                }
                else
                {
                    labels[i].Text = "- NOT LOADED -";
                }
            }

            

        }

        private void btnLoadMameFiles_Click(object sender, EventArgs e)
        {
            _dataLoadType = "mameFiles";
            bgwDataLoad.RunWorkerAsync();
            ctrlMain.Enabled = false;

        }

        private void btnSelectMameInfoFile_Click(object sender, EventArgs e)
        {
            tbMameInfoFile.Text = LauncherLib.getFileSelection("XML Files|*.xml");
        }

        private void btnSelectControlFile_Click(object sender, EventArgs e)
        {
            tbControlFile.Text = LauncherLib.getFileSelection("XML Files|*.xml");
        }

        private void btnSelectHistoryFile_Click(object sender, EventArgs e)
        {
            tbHistoryFile.Text = LauncherLib.getFileSelection("DAT Files|*.dat");
        }

        private void btnSelectCategoryFile_Click(object sender, EventArgs e)
        {
            tbCategoryFile.Text = LauncherLib.getFileSelection("ini Files|*.ini");
        }

        private void btnSelectNplayersFile_Click(object sender, EventArgs e)
        {
            tbNplayersFile.Text = LauncherLib.getFileSelection("ini Files|*.ini");
        }

        private void btnSelectCommandFile_Click(object sender, EventArgs e)
        {
            tbCommandFile.Text = LauncherLib.getFileSelection("DAT Files|*.dat");
        }

        private void btnGenerateMameInfo_Click(object sender, EventArgs e)
        {
            string outFile = LauncherLib.getNewFileSelection("*.xml|*.xml", "MameInfo.xml");

            if (outFile != "")
            {

                string error = "";
                if (LauncherLib.generateMameInfo(outFile, ref error))
                {
                    // no error, so dump the outfile name into dataload section
                    tbMameInfoFile.Text = outFile;
                }
                else
                {
                    MessageBox.Show(error, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }


        private void bgwDataLoad_DoWork(object sender, DoWorkEventArgs e)
        {
            string mameInfoFile = tbMameInfoFile.Text;
            string controlFile = tbControlFile.Text;
            string historyFile = tbHistoryFile.Text;
            string categoryFile = tbCategoryFile.Text;
            string nPlayersFile = tbNplayersFile.Text;
            string commandFile = tbCommandFile.Text;

            _error = "";

            switch(_dataLoadType) {
                case "mameFiles" :
                    LauncherLib.populateMameDB(mameInfoFile, controlFile, historyFile, categoryFile, nPlayersFile, commandFile, ref configStatus, ref _error);
                    break;
                case "populateGames" :
                    LauncherLib.populateGameEntries(chkGameReload.Checked, ref configStatus, ref _error);
                    break;
            }
        }

        private void bgwDataLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ctrlMain.Enabled = true;

            if (_error != "")
            {
                string errorPrefix = (_dataLoadType == "mameFiles"?"Error loading mame files":"Error populating game entries");
                MessageBox.Show(errorPrefix + Environment.NewLine + _error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            } 

            if(_dataLoadType=="mameFiles")
                populateFileMetaData();
        }

        #endregion

        #region Games

        private void btnPopulateGames_Click(object sender, EventArgs e)
        {

            _dataLoadType = "populateGames";
            bgwDataLoad.RunWorkerAsync();
            ctrlMain.Enabled = false;

        }


        private void populateCustomGameList()
        {
            // get a list of all custom games, and add to drop down list

            _customGameList = new List<KeyValuePair<int, string>>();
            foreach (KeyValuePair<int, string> item in LauncherLib.getCustomGameList())
                _customGameList.Add(item);


            lbCustomGames.Items.Clear();
            lbCustomGames.DataSource = _customGameList;
            lbCustomGames.DisplayMember = "Value";
            lbCustomGames.ValueMember = "Key";
        }

        private void btnNewCustomGame_Click(object sender, EventArgs e)
        {
            loadCustomGamePropertyGrid(0);
        }

        private void loadCustomGamePropertyGrid(int CustomGameID)
        {
            CustomGame config = null;

            if (CustomGameID > 0)
                config = LauncherLib.getCustomGame(CustomGameID);
            else if (CustomGameID == 0)
            {
                // new entry added
                config = new CustomGame();
                int minId = 0;

                if (_customGameList.Count > 0)
                    minId = (from x in _customGameList select x.Key).Min();

                if (minId >= 0)
                    minId = -1;
                else
                    minId--;

                _customGameList.Add(new KeyValuePair<int, string>(minId, "NEW CUSTOM GAME"));

                lbCustomGames.DataSource = null;

                lbCustomGames.DataSource = _customGameList;
                lbCustomGames.DisplayMember = "Value";
                lbCustomGames.ValueMember = "Key";

                lbCustomGames.SelectedIndex = lbCustomGames.Items.Count - 1;
            }
            else
            {
                config = new CustomGame();

            }


            // clear all existing items
            pgCustomGame.Item.Clear();

            string category = "Details";
            pgCustomGame.Item.Add("Name", config.Name ?? "", false, category, "Name used to identify the custom game.", true);
            pgCustomGame.Item.Add("Description", config.Description ?? "", false, category, "Description of the game, displayed in some screens.", true);


            category = "Resources";

            pgCustomGame.Item.Add("Executable", config.Executable ?? "", false, category, "The executable used to run the game.", true);
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].UseFileNameEditor = true;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameFilter = "All files (*.*)|*.*";

            pgCustomGame.Item.Add("Movie File", config.Movie ?? "", false, category, "The movie preview of the game.", true);
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].UseFileNameEditor = true;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameFilter = "All files (*.*)|*.*";

            pgCustomGame.Item.Add("Snapshot", config.Snapshot ?? "", false, category, "The image preview of the game", true);
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].UseFileNameEditor = true;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameDialogType = PropertyGridEx.UIFilenameEditor.FileDialogType.LoadFileDialog;
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].FileNameFilter = "All files (*.*)|*.*";



            category = "Pre/Post Operations";
            pgCustomGame.Item.Add("Pre Load", config.PreLoad ?? "", false, category, "Executed before the game is launched. For example, load a memory resident util.", true);
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].OnClick += ShowMultiLineStringEditor;
            pgCustomGame.Item.Add("Post Load", config.PostLoad ?? "", false, category, "Executed after the game has exited. For example, unload a memory resident util.", true);
            pgCustomGame.Item[pgCustomGame.Item.Count - 1].OnClick += ShowMultiLineStringEditor;

            //pgCustomGame.Item.Add("Key Mappings", config.KeyMappingString(), false, category, "Remaps keys for the duration of the game being executed. Use custom editor instead of manually modifying.", true);
            //pgCustomGame.Item[pgCustomGame.Item.Count - 1].OnClick += ShowKeyMappingEditor;

            pgCustomGame.Refresh();

        }



        private void saveCustomGamePropertyGrid()
        {
            CustomGame config = new CustomGame();

            int gameId = ((KeyValuePair<int, string>)lbCustomGames.SelectedItem).Key;
            config.GameID = gameId;

            string category = "Details";
            config.Name = getPropertyGridItem(pgCustomGame, "Name", category);
            config.Description = getPropertyGridItem(pgCustomGame, "Description", category);

            category = "Resources";
            config.Executable = getPropertyGridItem(pgCustomGame, "Executable", category);
            config.Movie = getPropertyGridItem(pgCustomGame, "Movie File", category);
            config.Snapshot = getPropertyGridItem(pgCustomGame, "Snapshot", category);
 
            category = "Pre/Post Operations";
            config.PreLoad = getPropertyGridItem(pgCustomGame, "Pre Load", category);
            config.PostLoad = getPropertyGridItem(pgCustomGame, "Post Load", category);
            config.KeyMappings = LauncherLib.StringToKeyMapping(getPropertyGridItem(pgCustomGame, "Key Mappings", category));

            string error = "";
            int newGameId = (int)LauncherLib.saveCustomGameConfig(config, ref error);
            if(newGameId == -1)
            {
                MessageBox.Show("Error saving custom game" + Environment.NewLine + error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // now update the dropdown with the correct info.
            int index = -1;
            for (int i = 0; i < _customGameList.Count; i++)
            {
                if (_customGameList[i].Key == gameId)
                {
                    index = i;
                }
            }

            KeyValuePair<int, string> newItem = new KeyValuePair<int, string>(newGameId, config.Name);
            _customGameList[index] = newItem;

            lbCustomGames.DataSource = null;

            lbCustomGames.DataSource = _customGameList;
            lbCustomGames.DisplayMember = "Value";
            lbCustomGames.ValueMember = "Key";

            lbCustomGames.SelectedIndex = index;


        }

        private void btnSaveCustomgame_Click(object sender, EventArgs e)
        {
            saveCustomGamePropertyGrid();
        }

        private void lbCustomGames_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lbCustomGames.SelectedItem != null)
            {

                int gameId = ((KeyValuePair<int, string>)lbCustomGames.SelectedItem).Key;
                loadCustomGamePropertyGrid(gameId);
            }
        }

        private void btnDeleteCustomGame_Click(object sender, EventArgs e)
        {
            if (lbCustomGames.SelectedItem != null)
            {

                int gameId = ((KeyValuePair<int, string>)lbCustomGames.SelectedItem).Key;
                if (gameId > 0)
                {
                    string error = "";
                    if (!LauncherLib.deleteCustomGame(gameId, ref error))
                    {
                        MessageBox.Show("Error deleting custom game" + Environment.NewLine + error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }


                    _customGameList.RemoveAt(lbCustomGames.SelectedIndex);

                    lbCustomGames.DataSource = null;
                    //lbEmulator.Items.Clear();

                    lbCustomGames.DataSource = _customGameList;
                    lbCustomGames.DisplayMember = "Value";
                    lbCustomGames.ValueMember = "Key";


                    if (_customGameList.Count > 0)
                        lbCustomGames.SelectedIndex = lbCustomGames.Items.Count - 1;
                    else
                    {
                        pgCustomGame.Item.Clear();
                        pgCustomGame.Refresh();
                    }
                }
            }
        }


        #endregion

        #region DB Maintenance
        private void btnExecuteScript_Click(object sender, EventArgs e)
        {
            string message = LauncherLib.executeDBScript(true);
            if (message.Trim() != "")
                MessageBox.Show(message);
            else
                MessageBox.Show("Script execution complete.");
        }

        #endregion

        #region Utils

        private void showHideCopyMameRomButton()
        {
            if (LauncherLib.HasMameEmulatorDefined())
                btnCopyRomFiles.Enabled = true;
            else
                btnCopyRomFiles.Enabled = false;
        }



        private void btnCopyRomFiles_Click(object sender, EventArgs e)
        {
            frmSearch searchForm = new frmSearch(-1, txtMameRomSourceFolder.Text);
            // searchForm.FormClosed += new FormClosedEventHandler(searchForm_FormClosed);
            searchForm.ShowDialog();

            searchForm.Dispose();
        }

        private void btnChooseMameRomSourceFolder_Click(object sender, EventArgs e)
        {
            txtMameRomSourceFolder.Text = LauncherLib.getFolderSelection();
        }



        private void btnGenerateMissingResourcesReport_Click(object sender, EventArgs e)
        {
            string fileName = "";
            fileName = LauncherLib.getNewFileSelection("*.htm|*.htm", "MissingResourcesReport.htm");

            if (fileName != null && fileName != "")
            {
                if (LauncherLib.generateMissingResourceReport(fileName))
                {
                    //MessageBox.Show("Complete");
                    LauncherLib.displayHTMLDocument(fileName);

                }
            }


        }

        private void btnGameReport_Click(object sender, EventArgs e)
        {
            string fileName = "";
            fileName = LauncherLib.getNewFileSelection("*.htm|*.htm", "GamesReport.htm");

            if (fileName != null && fileName != "")
            {
                if (LauncherLib.generateGamesReport(fileName))
                {
                    //MessageBox.Show("Complete");
                    LauncherLib.displayHTMLDocument(fileName);

                }
            }
        }

        #endregion

        #region Music
        private void btnScanForMusic_Click(object sender, EventArgs e)
        {
            LauncherLib.populateMusic();
            MessageBox.Show("Scan Complete");
        }

        #endregion

        private void btnRemapDriveLetter_Click(object sender, EventArgs e)
        {
            string fromDriveLetter = tbFromDriveLetter.Text.ToString().Trim();
            string toDriveLetter = tbToDriveLetter.Text.ToString().Trim();

            if (fromDriveLetter != "" && toDriveLetter != "")
            {
                LauncherLib.remapDriveLetters(fromDriveLetter, toDriveLetter);
            }
            MessageBox.Show("Drives remapped.");

            // refresh the emulator page
            if (lbEmulator.SelectedItem != null)
            {
                int emulatorId = ((KeyValuePair<int, string>)lbEmulator.SelectedItem).Key;
                loadEmulatorPropertyGrid(emulatorId);
            }
        }

        private void btnSmartRetrieveControls_Click(object sender, EventArgs e)
        {
            SmartRetrieve frm = new SmartRetrieve("control");
            frm.ShowDialog();
            tbControlFile.Text = frm.DownloadedFile;

            frm.Dispose();

        }

        private void btnSmartRetrieveCommand_Click(object sender, EventArgs e)
        {

            SmartRetrieve frm = new SmartRetrieve("command");
            frm.ShowDialog();
            tbCommandFile.Text = frm.DownloadedFile;

            frm.Dispose();
        }

        private void btnSmartRetrieveNplayer_Click(object sender, EventArgs e)
        {

            SmartRetrieve frm = new SmartRetrieve("nplayer");
            frm.ShowDialog();
            tbNplayersFile.Text = frm.DownloadedFile;

            frm.Dispose();
        }

        private void btnSmartRetrieveCatVer_Click(object sender, EventArgs e)
        {

            SmartRetrieve frm = new SmartRetrieve("catver");
            frm.ShowDialog();
            tbCategoryFile.Text = frm.DownloadedFile;

            frm.Dispose();
        }

        private void btnSmartRetrieveHistory_Click(object sender, EventArgs e)
        {

            SmartRetrieve frm = new SmartRetrieve("history");
            frm.ShowDialog();
            tbHistoryFile.Text = frm.DownloadedFile;

            frm.Dispose();
        }













    }
}
